/*
 * Copyright (C) 2011 Mette Bank, Rikke Jensen, Kenneth Brodersen, Thomas Pedersen
 * 
 * This file is part of digiPECS.
 * 
 * digiPECS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * digiPECS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with digiPECS.  If not, see <http://www.gnu.org/licenses/>.
 */

package sw6.digipecs.model;

import java.util.ArrayList;

import sw6.digipecs.database.DBAdapter;
import sw6.digipecs.database.IDCursor;
import sw6.digipecs.exceptions.IDNotFoundException;
import sw6.digipecs.exceptions.ImageIsEmptyException;
import sw6.digipecs.exceptions.NotOpenException;
import sw6.digipecs.exceptions.NotSupportedException;
import android.content.Context;
import android.database.Cursor;
import android.util.Log;

public class PECSBook {
	
	private ArrayList<ExtImage> mPictures;
	private DBAdapter mDBAdapter;
	private IDCursor mCursor;
	static private final int PICTURES_IN_PAGE = 20;
	private int mCurrentPage = 0;
	private ArrayList<PECSBookChangeListener> mListeners;
	private boolean mIsOpen = false;
	private Context mContext;
	private boolean mShowActiveOnly;
	private int mSituation;
	
	public interface PECSBookChangeListener {
		public void bookChanged();
	}
	
	/**
	 * \remark Remember to close book
	 * @param context
	 * @param showActiveOnly
	 * @param situation Set this to -1 for all situations
	 */
	public PECSBook(Context context, boolean showActiveOnly, int situation) {
		mPictures = new ArrayList<ExtImage>();
		mDBAdapter = new DBAdapter(context);
		mListeners = new ArrayList<PECSBookChangeListener>();
		mContext = context;
		mShowActiveOnly = showActiveOnly;
		mSituation = situation;
		
		open();
	}
	
	public void loadCursor() {
		if (mShowActiveOnly) {
			if (mSituation >= 0) {
				mCursor = mDBAdapter.fetchActivePicturesForSituation(mSituation);
			} else {
				throw new NotSupportedException("Show active pictures only for all situations is not supported");
			}
		} else {
			if (mSituation >= 0) {
				mCursor = mDBAdapter.fetchAllPicturesForSituation(mSituation);
			} else {
				mCursor = mDBAdapter.fetchPictures();
			}
		}
	}
	
	public void open() {
		if (mIsOpen) return;
		
		Log.i("sw6", "PECS Book opens");
		
		// TODO How do I find out if the database is modified when running?
		// TODO What happens if data in the database changes while we are using this cursor ? (Rerun query at each page update?)
		mDBAdapter.open();
		loadCursor();
		
		Log.i("sw6", "Pictures in PECSBook: " + mCursor.getCount());
		
		mIsOpen = true;
		readPage();
	}
	
	public void close() {
		Log.i("sw6", "PECS Book closes");
		mCursor.close();
		mDBAdapter.close();
		
		mIsOpen = false;
	}
	
	private void readPictures(ArrayList<ExtImage> list, int first, int count) {
		if (!mIsOpen) throw new NotOpenException();
		final IDCursor cursor = mCursor;
		
		if (cursor.moveToPosition(first)) {
			for (int i = 0; i < count; i++) {
				try {
					final ExtImage image = new ExtImage(mContext, mCursor.getPictureID()); 
					list.add(image);
				} catch (IDNotFoundException e) {
					Log.e("sw6", "The ID (" + mCursor.getPictureID() + ") is not valid, though it should be, because it comes from within the database!");
					e.printStackTrace();
				}
				
				// Move the cursor			
				if (!cursor.moveToNext()) break;
			}
		}
	}
	
	// This is a bit hackish .. using cursor adapters and handling this through cursors should be preferred
	private void readPage() {
		// Make the list ready
		mPictures.clear();
		readPictures(mPictures, mCurrentPage * PICTURES_IN_PAGE, PICTURES_IN_PAGE);
		
		// Tell everyone we changed the list
		notifyAllListeners();
	}
	
	// TODO This is used in admin pages, but shouldn't this show pages as the user interface???
	// TODO Shouldn't this be moved to ExtImage (static function) as in Situation.java
	public ArrayList<ExtImage> getAllPictures() {
		if (!mIsOpen) throw new NotOpenException();
		final Cursor cursor = mCursor;
		ArrayList<ExtImage> list = new ArrayList<ExtImage>();
		
		readPictures(list, 0, cursor.getCount());
		
		return list;
	}
	
	private void notifyAllListeners() {
		for (PECSBookChangeListener listener : mListeners) {
			listener.bookChanged();
		}
	}
	
	public int getPageCount() {
		if (!mIsOpen) throw new NotOpenException();
		final float pics = mCursor.getCount();
		final float inPage = PICTURES_IN_PAGE;
		final float pages = pics / inPage;
		
		return (int) Math.ceil(pages);
	}
	
	public void setPage(int i) {
		// Page number too low (set to 0)
		if (i < 0) i = 0;
		
		// Page number too high (set to highest page)
		final int pages = getPageCount();
		if (i >= pages) i = pages - 1;
		
		// Set and read page
		mCurrentPage = i;
		readPage();
	}
	
	// Note remember to use addListener as well, if you want to be notified about changes to list, eg. page change.
	public ArrayList<ExtImage> getCurrentPage() {
		return mPictures;
	}
	
	public void addOnChangeListener(PECSBookChangeListener listener) {
		mListeners.add(listener);
	}

	public int getPage() {
		return mCurrentPage;
	}

	public void swapPosition(ExtImage image, ExtImage image2) throws ImageIsEmptyException {
		try {
			mDBAdapter.swapPicturePositionInSituation(mSituation, image.getId(), image2.getId());
			
			// Book needs total reload to reflect the change
			loadCursor();
			readPage();
			notifyAllListeners();
		} catch (IDNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
}
